<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=2">
<meta name="theme-color" content="#222">
<meta name="generator" content="Hexo 4.2.0">
  <link rel="apple-touch-icon" sizes="180x180" href="/images/apple-touch-icon-next.png">
  <link rel="icon" type="image/png" sizes="32x32" href="/images/favicon-32x32-next.png">
  <link rel="icon" type="image/png" sizes="16x16" href="/images/favicon-16x16-next.png">
  <link rel="mask-icon" href="/images/logo.svg" color="#222">

<link rel="stylesheet" href="/css/main.css">


<link rel="stylesheet" href="/lib/font-awesome/css/font-awesome.min.css">


<script id="hexo-configurations">
  var NexT = window.NexT || {};
  var CONFIG = {
    hostname: new URL('http://yoursite.com').hostname,
    root: '/',
    scheme: 'Pisces',
    version: '7.6.0',
    exturl: false,
    sidebar: {"position":"left","display":"post","padding":18,"offset":12,"onmobile":false},
    copycode: {"enable":false,"show_result":false,"style":null},
    back2top: {"enable":true,"sidebar":false,"scrollpercent":false},
    bookmark: {"enable":false,"color":"#222","save":"auto"},
    fancybox: false,
    mediumzoom: false,
    lazyload: false,
    pangu: false,
    comments: {"style":"tabs","active":null,"storage":true,"lazyload":false,"nav":null},
    algolia: {
      appID: '',
      apiKey: '',
      indexName: '',
      hits: {"per_page":10},
      labels: {"input_placeholder":"Search for Posts","hits_empty":"We didn't find any results for the search: ${query}","hits_stats":"${hits} results found in ${time} ms"}
    },
    localsearch: {"enable":false,"trigger":"auto","top_n_per_article":1,"unescape":false,"preload":false},
    path: '',
    motion: {"enable":true,"async":false,"transition":{"post_block":"fadeIn","post_header":"slideDownIn","post_body":"slideDownIn","coll_header":"slideLeftIn","sidebar":"slideUpIn"}}
  };
</script>

  <meta name="description" content="前言在日常的开发中很多时候都会遇到链接问题。比如，缺少模块、缺少库或者库版本不兼容导致的链接问题；错误定义多个全局变量导致程序运行产生不可预知的错误。为了减少这些错误的发生，我们应当理解链接过程。本文主要讨论静态链接。">
<meta property="og:type" content="article">
<meta property="og:title" content="Static Link">
<meta property="og:url" content="http://yoursite.com/2021/04/19/Static-Link/index.html">
<meta property="og:site_name" content="SRCNN">
<meta property="og:description" content="前言在日常的开发中很多时候都会遇到链接问题。比如，缺少模块、缺少库或者库版本不兼容导致的链接问题；错误定义多个全局变量导致程序运行产生不可预知的错误。为了减少这些错误的发生，我们应当理解链接过程。本文主要讨论静态链接。">
<meta property="og:locale" content="en_US">
<meta property="article:published_time" content="2021-04-19T15:46:56.000Z">
<meta property="article:modified_time" content="2021-11-30T15:36:20.276Z">
<meta property="article:author" content="Z.J. Jiang">
<meta property="article:tag" content="SISR">
<meta property="article:tag" content=" FH">
<meta name="twitter:card" content="summary">

<link rel="canonical" href="http://yoursite.com/2021/04/19/Static-Link/">


<script id="page-configurations">
  // https://hexo.io/docs/variables.html
  CONFIG.page = {
    sidebar: "",
    isHome: false,
    isPost: true
  };
</script>

  <title>Static Link | SRCNN</title>
  






  <noscript>
  <style>
  .use-motion .brand,
  .use-motion .menu-item,
  .sidebar-inner,
  .use-motion .post-block,
  .use-motion .pagination,
  .use-motion .comments,
  .use-motion .post-header,
  .use-motion .post-body,
  .use-motion .collection-header { opacity: initial; }

  .use-motion .site-title,
  .use-motion .site-subtitle {
    opacity: initial;
    top: initial;
  }

  .use-motion .logo-line-before i { left: initial; }
  .use-motion .logo-line-after i { right: initial; }
  </style>
</noscript>

</head>

<body itemscope itemtype="http://schema.org/WebPage">
  <div class="container use-motion">
    <div class="headband"></div>

    <header class="header" itemscope itemtype="http://schema.org/WPHeader">
      <div class="header-inner"><div class="site-brand-container">
  <div class="site-meta">

    <div>
      <a href="/" class="brand" rel="start">
        <span class="logo-line-before"><i></i></span>
        <span class="site-title">SRCNN</span>
        <span class="logo-line-after"><i></i></span>
      </a>
    </div>
        <p class="site-subtitle">SISR-FH</p>
  </div>

  <div class="site-nav-toggle">
    <div class="toggle" aria-label="Toggle navigation bar">
      <span class="toggle-line toggle-line-first"></span>
      <span class="toggle-line toggle-line-middle"></span>
      <span class="toggle-line toggle-line-last"></span>
    </div>
  </div>
</div>


<nav class="site-nav">
  
  <ul id="menu" class="menu">
        <li class="menu-item menu-item-home">

    <a href="/" rel="section"><i class="fa fa-fw fa-home"></i>Home</a>

  </li>
        <li class="menu-item menu-item-tags">

    <a href="/tags/" rel="section"><i class="fa fa-fw fa-tags"></i>Tags</a>

  </li>
        <li class="menu-item menu-item-categories">

    <a href="/categories/" rel="section"><i class="fa fa-fw fa-th"></i>Categories</a>

  </li>
        <li class="menu-item menu-item-archives">

    <a href="/archives/" rel="section"><i class="fa fa-fw fa-archive"></i>Archives</a>

  </li>
  </ul>

</nav>
</div>
    </header>

    
  <div class="back-to-top">
    <i class="fa fa-arrow-up"></i>
    <span>0%</span>
  </div>


    <main class="main">
      <div class="main-inner">
        <div class="content-wrap">
          

          <div class="content">
            

  <div class="posts-expand">
      
  
  
  <article itemscope itemtype="http://schema.org/Article" class="post-block " lang="en">
    <link itemprop="mainEntityOfPage" href="http://yoursite.com/2021/04/19/Static-Link/">

    <span hidden itemprop="author" itemscope itemtype="http://schema.org/Person">
      <meta itemprop="image" content="/images/avatar.gif">
      <meta itemprop="name" content="Z.J. Jiang">
      <meta itemprop="description" content="about the single image super-resolution and face hallucination">
    </span>

    <span hidden itemprop="publisher" itemscope itemtype="http://schema.org/Organization">
      <meta itemprop="name" content="SRCNN">
    </span>
      <header class="post-header">
        <h1 class="post-title" itemprop="name headline">
          Static Link
        </h1>

        <div class="post-meta">
            <span class="post-meta-item">
              <span class="post-meta-item-icon">
                <i class="fa fa-calendar-o"></i>
              </span>
              <span class="post-meta-item-text">Posted on</span>

              <time title="Created: 2021-04-19 23:46:56" itemprop="dateCreated datePublished" datetime="2021-04-19T23:46:56+08:00">2021-04-19</time>
            </span>
              <span class="post-meta-item">
                <span class="post-meta-item-icon">
                  <i class="fa fa-calendar-check-o"></i>
                </span>
                <span class="post-meta-item-text">Edited on</span>
                <time title="Modified: 2021-11-30 23:36:20" itemprop="dateModified" datetime="2021-11-30T23:36:20+08:00">2021-11-30</time>
              </span>
            <span class="post-meta-item">
              <span class="post-meta-item-icon">
                <i class="fa fa-folder-o"></i>
              </span>
              <span class="post-meta-item-text">In</span>
                <span itemprop="about" itemscope itemtype="http://schema.org/Thing">
                  <a href="/categories/C/" itemprop="url" rel="index">
                    <span itemprop="name">C</span>
                  </a>
                </span>
            </span>

          

        </div>
      </header>

    
    
    
    <div class="post-body" itemprop="articleBody">

      
        <h1 id="前言"><a href="#前言" class="headerlink" title="前言"></a>前言</h1><p>在日常的开发中很多时候都会遇到链接问题。比如，缺少模块、缺少库或者库版本不兼容导致的链接问题；错误定义多个全局变量导致程序运行产生不可预知的错误。为了减少这些错误的发生，我们应当理解链接过程。本文主要讨论静态链接。</p>
<a id="more"></a>
<h1 id="Example"><a href="#Example" class="headerlink" title="Example"></a>Example</h1><p>接下来主要通过下面简单的例子来介绍静态链接。<br><figure class="highlight angelscript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line">main.c:</span><br><span class="line"><span class="built_in">int</span> sum(<span class="built_in">int</span> *a, <span class="built_in">int</span> n);</span><br><span class="line"></span><br><span class="line"><span class="built_in">int</span> <span class="built_in">array</span>[<span class="number">2</span>] = &#123;<span class="number">1</span>, <span class="number">2</span>&#125;;</span><br><span class="line"></span><br><span class="line"><span class="built_in">int</span> main()</span><br><span class="line">&#123;</span><br><span class="line">    <span class="built_in">int</span> val = sum(<span class="built_in">array</span>, <span class="number">2</span>);</span><br><span class="line">    <span class="keyword">return</span> val;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><br><figure class="highlight angelscript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><span class="line">sum.c</span><br><span class="line"><span class="built_in">int</span> sum(<span class="built_in">int</span> *a, <span class="built_in">int</span> n)</span><br><span class="line">&#123;</span><br><span class="line">    <span class="built_in">int</span> i, s = <span class="number">0</span>;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">for</span> (i = <span class="number">0</span>; i &lt; n; i++) </span><br><span class="line">    &#123;</span><br><span class="line">        s += a[i];</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="keyword">return</span> s;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><br>使用gcc命令将上述两文件编译成可执行程序。</p>
<p>我们使用最简单的例子来学习静态链接。main函数初始化一个int形的array数组。然后调用sum函数计算array个各元素的和。</p>
<h1 id="静态链接"><a href="#静态链接" class="headerlink" title="静态链接"></a>静态链接</h1><p>为了构造可执行文件，链接器必须完成两个主要任务</p>
<ol>
<li>符号解析。一个函数，全局变量或者静态变量可以是一个符号，局部变量在栈空间分配，不是一个符号。符号解析的目的是将每个符号引用正好一个符号定义关联起来。</li>
<li>重定位。编译器和链接器生成以地址0开始的代码段和数据段。这些地址并不是程序执行时的真正地址，因此需要通过链接器修正所有符号的引用，使它们的地址为程序执行时的真正地址。</li>
</ol>
<h1 id="目标文件"><a href="#目标文件" class="headerlink" title="目标文件"></a>目标文件</h1><p>目标文件有三种形式</p>
<ul>
<li>可重定位文件。包含代码和数据，可以被用来链接成可执行文件或共享目标文件。</li>
<li>可执行文件。可直接复制到内存并执行。</li>
<li>共享目标文件。一种特殊类型的可重定位目标文件，可以在加载或者运行时被动态地加载进内存并链接。</li>
</ul>
<h1 id="可重定位目标文件"><a href="#可重定位目标文件" class="headerlink" title="可重定位目标文件"></a>可重定位目标文件</h1><p>目标文件将代码，数据，符号表，调试信息等不同属性的信息，以段的形式存储。一个目标文件中有多个段。</p>
<ul>
<li>ELF头。可以使用readelf命令查看ELF文件头信息。ELF文件头定义了ELF魔数、文件机器字节长度、数据存储方式、版本、运行平台、ABI版本、ELF重定位类型、硬件平台、硬件平台版本、入口地址、程序头入口和长度、段表的位置和长度及段的数量等。</li>
<li>.text。已编译程序的机器代码</li>
<li>.rodata。只读数据，例如printf语句中的格式化输出字符串。</li>
<li>.data。已初始化的全局和静态变量。</li>
<li>.bss。未初始化或初始化为0的全局和静态变量。未初始化变量不占用任何磁盘空间。运行是，在内存分配这些变量，初始值为0</li>
<li>.symtab。符号表，存放程序中定义和引用的函数和全局变量的信息。</li>
<li>.rel.text。代码段重定位表。根据其中存储的符号offset值可以计算出符号正确地址，</li>
<li>.rel.data。数据段重定位表。</li>
<li>.strtab。字符串表。保存字符串，符号的名字，段名等。</li>
</ul>
<h1 id="符号和符号表"><a href="#符号和符号表" class="headerlink" title="符号和符号表"></a>符号和符号表</h1><p>每个目标文件都有一个相应的符号表，这个表记录了目标文件定义和引用的所有符号。一般有三种不同的符号：</p>
<ul>
<li>定义在本目标文件的全局符号，可被其他目标文件使用。对应在本目标文件中定义的非static的函数和全局变量。</li>
<li>定义在其他目标文件，在本目标文件中引用的全局变量。对应在其他目标文件定义的非static的函数和全局变量。</li>
<li>在本目标文件定义和引用的局部符号。对应static修饰的函数或变量。</li>
</ul>
<h2 id="符号表的结构"><a href="#符号表的结构" class="headerlink" title="符号表的结构"></a>符号表的结构</h2><figure class="highlight arduino"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">typedef</span> <span class="class"><span class="keyword">struct</span></span></span><br><span class="line"><span class="class">&#123;</span></span><br><span class="line">    <span class="keyword">int</span>	st_name; <span class="comment">/* string table offset */</span></span><br><span class="line">    <span class="keyword">char</span> type:<span class="number">4</span>, <span class="comment">/* Function or data (4bits) */</span></span><br><span class="line">         bingding:<span class="number">4</span>;  <span class="comment">/* Local or global (4bits) */</span></span><br><span class="line">    <span class="keyword">char</span> reserved;  <span class="comment">/* unused */</span></span><br><span class="line">    short	section; <span class="comment">/* section header index */</span></span><br><span class="line">    <span class="keyword">long</span>	value; <span class="comment">/* section offset or absolute address */</span></span><br><span class="line">    <span class="keyword">long</span>	<span class="built_in">size</span>;  <span class="comment">/* object size in bytes */</span></span><br><span class="line">&#125; Elf64_Sym;</span><br></pre></td></tr></table></figure>
<ul>
<li>name。字符串表的偏移量。</li>
<li>type。符号类型</li>
<li>binding。符号是本地的还是全局的。</li>
<li>section。到段表(section header)的索引</li>
<li>value。表示偏移量或者绝对地址。</li>
<li>size。符号的大小。<br>可以使用readelf工具分析上文提到的例子的目标文件。<br><code>readelf -s main.o</code>可以得到以下输出：<figure class="highlight routeros"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line">Num:    Value          Size<span class="built_in"> Type </span>   Bind   Vis      Ndx Name</span><br><span class="line">  0: 0000000000000000     0 NOTYPE  LOCAL <span class="built_in"> DEFAULT </span> UND </span><br><span class="line">  1: 0000000000000000     0 FILE    LOCAL <span class="built_in"> DEFAULT </span> ABS main.c</span><br><span class="line">  2: 0000000000000000     0 SECTION LOCAL <span class="built_in"> DEFAULT </span>   1 </span><br><span class="line">  3: 0000000000000000     8 OBJECT  GLOBAL<span class="built_in"> DEFAULT </span>   3 array</span><br><span class="line">  4: 0000000000000000    33 FUNC    GLOBAL<span class="built_in"> DEFAULT </span>   1 main</span><br><span class="line">  5: 0000000000000000     0 NOTYPE  GLOBAL<span class="built_in"> DEFAULT </span> UND _GLOBAL_OFFSET_TABLE_</span><br><span class="line">  6: 0000000000000000     0 NOTYPE  GLOBAL<span class="built_in"> DEFAULT </span> UND sum</span><br></pre></td></tr></table></figure>
可以得知符号main是一个位于.text段偏移量为0的33字节函数。array是一个位于.data段的偏移量为0的8字节符号。</li>
</ul>
<h1 id="符号解析"><a href="#符号解析" class="headerlink" title="符号解析"></a>符号解析</h1><h2 id="解析多重定义的全局符号"><a href="#解析多重定义的全局符号" class="headerlink" title="解析多重定义的全局符号"></a>解析多重定义的全局符号</h2><p>函数和已初始化的全局变量是强符号，未初始化的全局变量是弱符号。针对强弱符号的概念，linux链接器使用如下规则处理多重定义的符号名</p>
<ul>
<li>规则1: 不允许强符号被多次定义</li>
<li>规则2: 如果一个强符号和多个弱符号同名，那么选择强符号。</li>
<li>规则3: 如果有多个弱符号同名，那么从这些弱符号中任意选择一个。(程序员自我修养中说到是选择占用空间最大的符号。)</li>
</ul>
<ol>
<li><p>example 1</p>
<figure class="highlight angelscript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">int</span> a = <span class="number">0</span>;</span><br><span class="line"><span class="built_in">int</span> a = <span class="number">1</span>;</span><br><span class="line"><span class="built_in">int</span> main()</span><br><span class="line">&#123;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<p>符号a是一个强符号，被定义了两次。编译这段程序会提示：</p>
<figure class="highlight angelscript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line">test.c:<span class="number">2</span>:<span class="number">5</span>: error: redefinition of ‘a’</span><br><span class="line">    <span class="number">2</span> | <span class="built_in">int</span> a = <span class="number">1</span>;</span><br><span class="line">      |     ^</span><br><span class="line">test.c:<span class="number">1</span>:<span class="number">5</span>: note: previous definition of ‘a’ was here</span><br><span class="line">    <span class="number">1</span> | <span class="built_in">int</span> a = <span class="number">0</span>;</span><br><span class="line">      |     ^</span><br></pre></td></tr></table></figure>
</li>
<li><p>example 2:</p>
<figure class="highlight cpp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/* test.c */</span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string">&lt;stdio.h&gt;</span></span></span><br><span class="line"><span class="keyword">int</span> x = <span class="number">10000</span>;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">void</span> <span class="title">func</span><span class="params">(<span class="keyword">void</span>)</span></span>;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">int</span> <span class="title">main</span><span class="params">()</span></span></span><br><span class="line"><span class="function"></span>&#123;</span><br><span class="line">    func();</span><br><span class="line">    <span class="built_in">printf</span>(<span class="string">"x = %d\n"</span>, x);</span><br><span class="line">    <span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="comment">/* func.c */</span></span><br><span class="line"></span><br><span class="line"><span class="keyword">int</span> x;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">void</span> <span class="title">func</span><span class="params">()</span></span></span><br><span class="line"><span class="function"></span>&#123;</span><br><span class="line">    x = <span class="number">20000</span>;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
</li>
</ol>
<p><code>gcc -o main test.c func.c &amp;&amp; ./main</code>应该打印<code>x = 20000</code><br>然而，实际上在我的电脑测试并不能成功通过编译。gcc版本是10.2.0。经查证，gcc 10.0以上的版本编译默认从-fcommon转到-fno-common.-fno-common选项告诉链接器，遇到重定义符号，就触发一个错误。</p>
<p>使用<code>gcc -o main test.c func.c -fcommon &amp;&amp; ./main</code>打印<code>x = 20000</code>。</p>
<ol>
<li>example3<figure class="highlight cpp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/* test.c */</span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string">&lt;stdio.h&gt;</span></span></span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">void</span> <span class="title">func</span><span class="params">(<span class="keyword">void</span>)</span></span>;</span><br><span class="line"></span><br><span class="line"><span class="keyword">int</span> x = <span class="number">20000</span>;</span><br><span class="line"><span class="keyword">int</span> y = <span class="number">10000</span>;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">int</span> <span class="title">main</span><span class="params">()</span></span></span><br><span class="line"><span class="function"></span>&#123;</span><br><span class="line">    func();</span><br><span class="line">    <span class="built_in">printf</span>(<span class="string">"x = 0x%x y = 0x%x \n"</span>, x, y);</span><br><span class="line">    <span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="comment">/* func.c */</span></span><br><span class="line"><span class="keyword">double</span> x;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">void</span> <span class="title">func</span><span class="params">()</span></span></span><br><span class="line"><span class="function"></span>&#123;</span><br><span class="line">    x = <span class="number">-0.0</span>;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
</li>
</ol>
<p>使用<code>gcc -o main test.c func.c -fcommon &amp;&amp; ./main</code>,编译过程只会产生一条警告信息<code>/usr/bin/ld: warning: alignment 4 of symbol x in /tmp/cc9XEYKu.o is smaller than 8 in /tmp/ccTc5xbh.o</code>输出<code>x=0x0 y = 80000000</code>(double数-0.0的二进制表示是0x80000000)。<br>这是一个微小的错误，但有时难以发现，可能在程序运行很久之后才表现出来。我们应该如何避免呢？</p>
<ul>
<li>使用全局变量时就将其初始化，使之成为一个强符号。</li>
<li>gcc编译的时候使用-fno-common选项</li>
<li>gcc编译使用-Werror选项，将所有警告都变成错误</li>
</ul>
<h1 id="静态库的链接顺序"><a href="#静态库的链接顺序" class="headerlink" title="静态库的链接顺序"></a>静态库的链接顺序</h1><p>静态库链接时候需要满足一定的顺序，有时改变某两个静态库的顺序就不能链接成功了。在符号解析阶段，链接器从左到右按照它们在编译器驱动程序命令行上出现的顺序来扫描可重定位目标文件和静态库。<strong>在命令行中，如果定义一个符号的库出现在引用这个符号的目标文件之前，那么引用就不能解析，链接会失败</strong></p>
<p>例如，可以重新编译上述的example2。使用下列命令将func.c编译成func.a静态库。<br><figure class="highlight autoit"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">gcc -c -fcommon <span class="function"><span class="keyword">func</span>.<span class="title">c</span></span></span><br><span class="line">gcc -c -fcommon test.c</span><br><span class="line">ar rcs libfunc.a <span class="function"><span class="keyword">func</span>.<span class="title">o</span></span></span><br></pre></td></tr></table></figure><br>使用下列命令可以成功编译。<br>gcc -static -o main test.o ./libfunc.a<br>而使用<br>gcc -static -o main ./libfunc.a test.o<br>则编译不通过，提示找不到符号<br><figure class="highlight vbnet"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">/usr/bin/ld: test.o: <span class="keyword">in</span> <span class="keyword">function</span> `main<span class="comment">':</span></span><br><span class="line">test.c:(.<span class="keyword">text</span>+<span class="number">0x5</span>): undefined reference <span class="keyword">to</span> `func<span class="comment">'</span></span><br><span class="line">collect2: <span class="keyword">error</span>: ld returned <span class="number">1</span> <span class="keyword">exit</span> status</span><br></pre></td></tr></table></figure><br>在命令行命令编译过程中，如果定义一个符号的库出现在引用这个符号的目标文件之前，那么引用就不能被解析，链接就会失败。因此尤其需要考虑库的位置。必须确保对符号的引用出现在该符号定义之前。</p>
<h1 id="重定位"><a href="#重定位" class="headerlink" title="重定位"></a>重定位</h1><p>编译器遇到对最终位置未知的目标引用，它就会产生一个重定位条目，告诉链接器在将目标文件合并成可执行文件时如何修改这个引用。代码的重定位条目放在.rel.text中。已初始化数据的重定位条目放在.rel.data中。下面结构体展示了重定位条目的格式。<br><figure class="highlight cpp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">typedef</span> <span class="class"><span class="keyword">struct</span></span></span><br><span class="line"><span class="class">&#123;</span></span><br><span class="line">    <span class="keyword">long</span> offset;    <span class="comment">/* offset of the referenct to relocate */</span></span><br><span class="line">    <span class="keyword">long</span> type:<span class="number">32</span>,   <span class="comment">/* relocation type */</span></span><br><span class="line">         symbol:<span class="number">32</span>; <span class="comment">/* Symbol table index */</span></span><br><span class="line">    <span class="keyword">long</span> addend;    <span class="comment">/* constant part of relocation expression */</span></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></p>
<ul>
<li>offset。需要被修改的引用的节偏移。</li>
<li>type。重定位类型，这里只讨论R_X86_64_PC32(相对地址引用)和R_X86_64_32(绝对地址引用)两种。</li>
<li>symbol。被修改引用应该指向的符号。</li>
<li>addend。相对地址引用中需要使用该值对被修改引用的值做位置偏移。<br>下面对本文最开始提到的main.o做重定位。使用<code>objdump -d main.o</code>查看反汇编代码。<figure class="highlight angelscript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><span class="line"><span class="number">0000000000000000</span> &lt;main&gt;:</span><br><span class="line">   <span class="number">0</span>:   <span class="number">55</span>                      push   %rbp</span><br><span class="line">   <span class="number">1</span>:   <span class="number">48</span> <span class="number">89</span> e5                mov    %rsp,%rbp</span><br><span class="line">   <span class="number">4</span>:   <span class="number">48</span> <span class="number">83</span> ec <span class="number">10</span>             sub    $<span class="number">0x10</span>,%rsp</span><br><span class="line">   <span class="number">8</span>:   be <span class="number">02</span> <span class="number">00</span> <span class="number">00</span> <span class="number">00</span>          mov    $<span class="number">0x2</span>,%esi</span><br><span class="line">   d:   <span class="number">48</span> <span class="number">8</span>d <span class="number">3</span>d <span class="number">00</span> <span class="number">00</span> <span class="number">00</span> <span class="number">00</span>    lea    <span class="number">0x0</span>(%rip),%rdi        # <span class="number">14</span> &lt;main+<span class="number">0x14</span>&gt;</span><br><span class="line">  <span class="number">14</span>:   e8 <span class="number">00</span> <span class="number">00</span> <span class="number">00</span> <span class="number">00</span>          call   <span class="number">19</span> &lt;main+<span class="number">0x19</span>&gt;</span><br><span class="line">  <span class="number">19</span>:   <span class="number">89</span> <span class="number">45</span> fc                mov    %eax,<span class="number">-0x4</span>(%rbp)</span><br><span class="line">  <span class="number">1</span>c:   <span class="number">8</span>b <span class="number">45</span> fc                mov    <span class="number">-0x4</span>(%rbp),%eax</span><br><span class="line">  <span class="number">1f</span>:   c9                      leave  </span><br><span class="line">  <span class="number">20</span>:   c3                      ret</span><br></pre></td></tr></table></figure>
对sum地址的引用为相对引用。相应的重定位条目r由4个字段组成:<figure class="highlight ini"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="attr">r.offset</span> = <span class="number">0</span>xf</span><br><span class="line"><span class="attr">r.symbol</span> = sum</span><br><span class="line"><span class="attr">r.type</span> = R_X<span class="number">86_64_</span>PC32</span><br><span class="line"><span class="attr">r.addend</span> = -<span class="number">4</span></span><br></pre></td></tr></table></figure>
现在假定编译器链接完之后，sum符号的地址是0x000000000000113a，main符号的地址是0x0000000000001119。那么如何根据这两个地址计算出sum引用的地址呢？<br>在调用call是，PC的值为call指令之后的指令地址，也就是0x0000000000001119 + 13 = 0x0000000000001132<br>也就是说0x0000000000001132 + x = 0x000000000000113a, 计算得到x为8。如下所示：<figure class="highlight angelscript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br></pre></td><td class="code"><pre><span class="line"><span class="number">0000000000001119</span> &lt;main&gt;:</span><br><span class="line">    <span class="number">1119</span>:       <span class="number">55</span>                      push   %rbp</span><br><span class="line">    <span class="number">111</span>a:       <span class="number">48</span> <span class="number">89</span> e5                mov    %rsp,%rbp</span><br><span class="line">    <span class="number">111</span>d:       <span class="number">48</span> <span class="number">83</span> ec <span class="number">10</span>             sub    $<span class="number">0x10</span>,%rsp</span><br><span class="line">    <span class="number">1121</span>:       be <span class="number">02</span> <span class="number">00</span> <span class="number">00</span> <span class="number">00</span>          mov    $<span class="number">0x2</span>,%esi</span><br><span class="line">    <span class="number">1126</span>:       <span class="number">48</span> <span class="number">8</span>d <span class="number">3</span>d fb <span class="number">2</span>e <span class="number">00</span> <span class="number">00</span>    lea    <span class="number">0x2efb</span>(%rip),%rdi        # <span class="number">4028</span> &lt;<span class="built_in">array</span>&gt;</span><br><span class="line">    <span class="number">112</span>d:       e8 <span class="number">08</span> <span class="number">00</span> <span class="number">00</span> <span class="number">00</span>          call   <span class="number">113</span>a &lt;sum&gt;</span><br><span class="line">    <span class="number">1132</span>:       <span class="number">89</span> <span class="number">45</span> fc                mov    %eax,<span class="number">-0x4</span>(%rbp)</span><br><span class="line">    <span class="number">1135</span>:       <span class="number">8</span>b <span class="number">45</span> fc                mov    <span class="number">-0x4</span>(%rbp),%eax</span><br><span class="line">    <span class="number">1138</span>:       c9                      leave  </span><br><span class="line">    <span class="number">1139</span>:       c3                      ret    </span><br><span class="line"></span><br><span class="line"><span class="number">000000000000113</span>a &lt;sum&gt;:</span><br><span class="line">    <span class="number">113</span>a:       <span class="number">55</span>                      push   %rbp</span><br><span class="line">    <span class="number">113</span>b:       <span class="number">48</span> <span class="number">89</span> e5                mov    %rsp,%rbp</span><br><span class="line">    <span class="number">113</span>e:       <span class="number">48</span> <span class="number">89</span> <span class="number">7</span>d e8             mov    %rdi,<span class="number">-0x18</span>(%rbp)</span><br><span class="line">    <span class="number">1142</span>:       <span class="number">89</span> <span class="number">75</span> e4                mov    %esi,<span class="number">-0x1c</span>(%rbp)</span><br><span class="line">    ......</span><br></pre></td></tr></table></figure>
<h1 id="结语"><a href="#结语" class="headerlink" title="结语"></a>结语</h1>本文简单介绍了静态链接。大量参考了《程序员的自我修养》和《深入理解计算机系统》这两本书。参考这两本书可以对静态链接有更深入的理解。</li>
</ul>

    </div>

    
    
    

      <footer class="post-footer">

        


        
    <div class="post-nav">
      <div class="post-nav-item">
    <a href="/2020/06/03/Redis-%E6%95%B4%E6%95%B0%E9%9B%86%E5%90%88/" rel="prev" title="Redis 整数集合">
      <i class="fa fa-chevron-left"></i> Redis 整数集合
    </a></div>
      <div class="post-nav-item">
    <a href="/2021/05/26/Linux-kernel-module/" rel="next" title="Linux kernel module">
      Linux kernel module <i class="fa fa-chevron-right"></i>
    </a></div>
    </div>
      </footer>
    
  </article>
  
  
  

  </div>


          </div>
          

<script>
  window.addEventListener('tabs:register', () => {
    let activeClass = CONFIG.comments.activeClass;
    if (CONFIG.comments.storage) {
      activeClass = localStorage.getItem('comments_active') || activeClass;
    }
    if (activeClass) {
      let activeTab = document.querySelector(`a[href="#comment-${activeClass}"]`);
      if (activeTab) {
        activeTab.click();
      }
    }
  });
  if (CONFIG.comments.storage) {
    window.addEventListener('tabs:click', event => {
      if (!event.target.matches('.tabs-comment .tab-content .tab-pane')) return;
      let commentClass = event.target.classList[1];
      localStorage.setItem('comments_active', commentClass);
    });
  }
</script>

        </div>
          
  
  <div class="toggle sidebar-toggle">
    <span class="toggle-line toggle-line-first"></span>
    <span class="toggle-line toggle-line-middle"></span>
    <span class="toggle-line toggle-line-last"></span>
  </div>

  <aside class="sidebar">
    <div class="sidebar-inner">

      <ul class="sidebar-nav motion-element">
        <li class="sidebar-nav-toc">
          Table of Contents
        </li>
        <li class="sidebar-nav-overview">
          Overview
        </li>
      </ul>

      <!--noindex-->
      <div class="post-toc-wrap sidebar-panel">
          <div class="post-toc motion-element"><ol class="nav"><li class="nav-item nav-level-1"><a class="nav-link" href="#前言"><span class="nav-number">1.</span> <span class="nav-text">前言</span></a></li><li class="nav-item nav-level-1"><a class="nav-link" href="#Example"><span class="nav-number">2.</span> <span class="nav-text">Example</span></a></li><li class="nav-item nav-level-1"><a class="nav-link" href="#静态链接"><span class="nav-number">3.</span> <span class="nav-text">静态链接</span></a></li><li class="nav-item nav-level-1"><a class="nav-link" href="#目标文件"><span class="nav-number">4.</span> <span class="nav-text">目标文件</span></a></li><li class="nav-item nav-level-1"><a class="nav-link" href="#可重定位目标文件"><span class="nav-number">5.</span> <span class="nav-text">可重定位目标文件</span></a></li><li class="nav-item nav-level-1"><a class="nav-link" href="#符号和符号表"><span class="nav-number">6.</span> <span class="nav-text">符号和符号表</span></a><ol class="nav-child"><li class="nav-item nav-level-2"><a class="nav-link" href="#符号表的结构"><span class="nav-number">6.1.</span> <span class="nav-text">符号表的结构</span></a></li></ol></li><li class="nav-item nav-level-1"><a class="nav-link" href="#符号解析"><span class="nav-number">7.</span> <span class="nav-text">符号解析</span></a><ol class="nav-child"><li class="nav-item nav-level-2"><a class="nav-link" href="#解析多重定义的全局符号"><span class="nav-number">7.1.</span> <span class="nav-text">解析多重定义的全局符号</span></a></li></ol></li><li class="nav-item nav-level-1"><a class="nav-link" href="#静态库的链接顺序"><span class="nav-number">8.</span> <span class="nav-text">静态库的链接顺序</span></a></li><li class="nav-item nav-level-1"><a class="nav-link" href="#重定位"><span class="nav-number">9.</span> <span class="nav-text">重定位</span></a></li><li class="nav-item nav-level-1"><a class="nav-link" href="#结语"><span class="nav-number">10.</span> <span class="nav-text">结语</span></a></li></ol></div>
      </div>
      <!--/noindex-->

      <div class="site-overview-wrap sidebar-panel">
        <div class="site-author motion-element" itemprop="author" itemscope itemtype="http://schema.org/Person">
  <p class="site-author-name" itemprop="name">Z.J. Jiang</p>
  <div class="site-description" itemprop="description">about the single image super-resolution and face hallucination</div>
</div>
<div class="site-state-wrap motion-element">
  <nav class="site-state">
      <div class="site-state-item site-state-posts">
          <a href="/archives/">
        
          <span class="site-state-item-count">42</span>
          <span class="site-state-item-name">posts</span>
        </a>
      </div>
      <div class="site-state-item site-state-categories">
            <a href="/categories/">
          
        <span class="site-state-item-count">11</span>
        <span class="site-state-item-name">categories</span></a>
      </div>
      <div class="site-state-item site-state-tags">
            <a href="/tags/">
          
        <span class="site-state-item-count">1</span>
        <span class="site-state-item-name">tags</span></a>
      </div>
  </nav>
</div>
  <div class="links-of-author motion-element">
      <span class="links-of-author-item">
        <a href="https://github.com/jzijin" title="GitHub → https:&#x2F;&#x2F;github.com&#x2F;jzijin" rel="noopener" target="_blank"><i class="fa fa-fw fa-github"></i>GitHub</a>
      </span>
      <span class="links-of-author-item">
        <a href="/atom.xml" title="RSS → &#x2F;atom.xml"><i class="fa fa-fw fa-rss"></i>RSS</a>
      </span>
  </div>


  <div class="links-of-blogroll motion-element">
    <div class="links-of-blogroll-title">
      <i class="fa fa-fw fa-link"></i>
      Links
    </div>
    <ul class="links-of-blogroll-list">
        <li class="links-of-blogroll-item">
          <a href="http://www.njust.edu.cn/" title="http:&#x2F;&#x2F;www.njust.edu.cn" rel="noopener" target="_blank">南京理工大学</a>
        </li>
        <li class="links-of-blogroll-item">
          <a href="http://ehall.njust.edu.cn/new/index.html" title="http:&#x2F;&#x2F;ehall.njust.edu.cn&#x2F;new&#x2F;index.html" rel="noopener" target="_blank">南京理工大学智慧服务</a>
        </li>
        <li class="links-of-blogroll-item">
          <a href="http://lib.njust.edu.cn/" title="http:&#x2F;&#x2F;lib.njust.edu.cn&#x2F;" rel="noopener" target="_blank">南京理工大学图书馆</a>
        </li>
    </ul>
  </div>

      </div>

    </div>
  </aside>
  <div id="sidebar-dimmer"></div>


      </div>
    </main>

    <footer class="footer">
      <div class="footer-inner">
        

<div class="copyright">
  
  &copy; 
  <span itemprop="copyrightYear">2022</span>
  <span class="with-love">
    <i class="fa fa-user"></i>
  </span>
  <span class="author" itemprop="copyrightHolder">Z.J. Jiang</span>
</div>
  <div class="powered-by">Powered by <a href="https://hexo.io/" class="theme-link" rel="noopener" target="_blank">Hexo</a> v4.2.0
  </div>
  <span class="post-meta-divider">|</span>
  <div class="theme-info">Theme – <a href="https://pisces.theme-next.org/" class="theme-link" rel="noopener" target="_blank">NexT.Pisces</a> v7.6.0
  </div>

        








      </div>
    </footer>
  </div>

  
  <script src="/lib/anime.min.js"></script>
  <script src="/lib/velocity/velocity.min.js"></script>
  <script src="/lib/velocity/velocity.ui.min.js"></script>

<script src="/js/utils.js"></script>

<script src="/js/motion.js"></script>


<script src="/js/schemes/pisces.js"></script>


<script src="/js/next-boot.js"></script>




  















  

  

  

</body>
</html>
